
#include	"Ray.h"
#include	"Plane.h"

#include	"Transform3D.h"

float Ray :: intersect ( const Plane& plane ) const
{
	float	denom = dir & plane.n;

	if ( fabs ( denom ) < EPS )
		return -1.0f;

	return - ( plane.dist + (org & plane.n) ) / denom;
}

void	Ray :: transform ( const Transform3D& transf )
{
	org = transf.transformPoint( org );
	dir = transf.getLinearPart () * dir;		// XXX: may be not normalized
}

/*bool	Ray ::intersect ( const BoundingBox& box )
{
    int	 i = 0;
	
    for ( int i = 0; i < 3 && fabs ( getDir () [i] ) < EPS; i++ )
        ;
		
    if ( i >= 3 )                 // some error, this means ray.dir == 0
        return false;
	
    float tMin = (box.getMinPoint() [i] - getOrigin () [i]) / getDir () [i];
    float tMax = (box.getMaxPoint() [i] - getOrigin () [i]) / getDir () [i];

    for ( i++; i < 3; i++ )
    {
        if ( fabs ( getDir () [i] ) < EPS )
            continue;

        float t1 = (box.getMinPoint() [i] - getOrigin () [i]) / getDir () [i];
        float t2 = (box.getMaxPoint() [i] - getOrigin () [i]) / getDir () [i];
		
        if ( t1 > tMin )          // take maximum of all t1's
            tMin = t1;
			
        if ( t2 < tMax )          // take minimum of all t2's
            tMax = t2;
			
        if ( tMin >= tMax)
            return false;
    }
	
    return true;
}*/

bool	Ray ::intersect ( const BoundingBox& box )
{
     bool inside = true;
	 int quadrant[3];
	 double coord[3];
	 double maxT[3];
	 double candidPlane[3];
	 int witchPlane;
	 for(int i = 0; i <3; i++)
	 
		 if(org[i] < box.getMinPoint()[i])
		 {
			 quadrant[i] = 1;
			 candidPlane[i] = box.getMinPoint()[i];
			 inside = false;
		 }
		 else if(org[i] > box.getMaxPoint()[i])
		 {
			 quadrant[i] = 0;
			 candidPlane[i] = box.getMinPoint()[i];
			 inside = false;
		 }
		 else
		 {
			 quadrant[i] = 2;
		 }
	 
		 if(inside)
			 return true;
		 for(int i = 0; i < 3; i++)
		 
			 if( (quadrant[i]!=2)&& (dir[i]!=0))
				 maxT[i] = (candidPlane[i] - org[i])/dir[i];
			 else
				 maxT[i] = -1;
		
		 witchPlane = 0;

		 for(int i =1; i<3;i++)
		 
			 if(maxT[witchPlane] < maxT[i])
				 witchPlane = i;
		 
		 if(maxT[witchPlane] < 0) return false;

		 for(int i = 0; i < 3; i++)
		
			 if(witchPlane!=i)
			 {
				 coord[i] = org[i] + maxT[witchPlane]*dir[i];
				 if (coord[i] < box.getMinPoint()[i] || coord[i] > box.getMaxPoint()[i])
				return (false);
			 }
		 
   return true;
}


bool    Ray::intersect(const BoundingSphere& sphere,float *dist)
{
	Vector3D rsVec = sphere.getCenter() - org;
	float rsLength = rsVec.dot(rsVec);
	float intersectDistA = rsVec.dot(dir);

	if(intersectDistA < 0 )
		return false;

	// Does the ray fall within the sphere's radius?
   float intersectDistB = (sphere.getRadius() * sphere.getRadius() ) - rsLength +(intersectDistA * intersectDistA);

	   // If not then no intersection with the ray.
	if(intersectDistB < 0)

		return false;

		// There is a hit so we record the results.
	if(dist != 0)
	*dist = intersectDistA - (float)sqrt(intersectDistB);
	
	return true;
}
